package com.hmall.item.controller;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.domain.PageQuery;
import com.hmall.common.utils.BeanUtils;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.po.ItemDoc;
import com.hmall.item.service.IItemService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Api(tags = "商品管理相关接口")
@RestController
@RequestMapping("/items")
@RequiredArgsConstructor
public class ItemController {

    private final IItemService itemService;
    private final RabbitTemplate rabbitTemplate;
    private final RedissonClient redissonClient;
    private final RedisTemplate redisTemplate;

    @ApiOperation("分页查询商品")
    @GetMapping("/page")
    public PageDTO<ItemDTO> queryItemByPage(PageQuery query) {
        // 1.分页查询
        Page<Item> result = itemService.page(query.toMpPage("update_time", false));
        // 2.封装并返回
        return PageDTO.of(result, ItemDTO.class);
    }

    @ApiOperation("根据id批量查询商品")
    @GetMapping
    public List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids){
        //return itemService.queryItemByIds(ids);
        return itemService.queryItemByIdsCache(ids);
    }

    @ApiOperation("根据id查询商品")
    @GetMapping("{id}")
    public ItemDTO queryItemById(@PathVariable("id") Long id) {
        return BeanUtils.copyBean(itemService.getById(id), ItemDTO.class);
    }

    @ApiOperation("新增商品")
    @PostMapping
    public void saveItem(@RequestBody ItemDTO itemDTO) {
        // 新增
        Item item = BeanUtils.copyBean(itemDTO, Item.class);
        boolean saved = itemService.save(item);
        updateToES(saved,item);
    }

    private void updateToES(boolean updated, Item item) {
        List<Item> list = new ArrayList<>();
        list.add(item);
        if(updated){
            List<ItemDoc> itemDocs = BeanUtil.copyToList(list, ItemDoc.class);
            rabbitTemplate.convertAndSend("item.sync.exchange", "item.save.sync", itemDocs);
        }
    }


    @ApiOperation("更新商品状态")
    @PutMapping("/status/{id}/{status}")
    public void updateItemStatus(@PathVariable("id") Long id, @PathVariable("status") Integer status){
        Item item = new Item();
        item.setId(id);
        item.setStatus(status);
        boolean updated = itemService.updateById(item);
        updateToES(updated,item);
    }

    @ApiOperation("更新商品")
    @PutMapping
    public void updateItem(@RequestBody ItemDTO itemDTO) throws InterruptedException {
        //获取分布式锁
        String lockKey = "hmall:lock:"+itemDTO.getId();
        RLock lock = redissonClient.getLock(lockKey);
        //争夺锁
        boolean tried = lock.tryLock(5, -1, TimeUnit.SECONDS);
        if(!tried){
            throw new RuntimeException("操作频繁，请稍后再试");
        }
        //实现数据库和Redis一致,数据库和ES一致
        // 不允许修改商品状态，所以强制设置为null，更新时，就会忽略该字段
        try {
            itemDTO.setStatus(null);
            // 更新MySQL
            Item item = BeanUtils.copyBean(itemDTO, Item.class);
            boolean updated = itemService.updateById(item);
            //更新Redis
            Item itemDB = itemService.getById(item.getId());
            redisTemplate.opsForValue().set("hmall:item"+item.getId(),itemDB, Duration.ofHours(1));
            //更新ES
            updateToES(updated,item);
        } finally {
            lock.unlock();
        }
    }

    @ApiOperation("根据id删除商品")
    @DeleteMapping("{id}")
    public void deleteItemById(@PathVariable("id") Long id) {
        boolean removed = itemService.removeById(id);
        if(removed){
            rabbitTemplate.convertAndSend("item.sync.exchange", "item.remove.sync", id);
        }
    }

    @ApiOperation("批量扣减库存")
    @PutMapping("/stock/deduct")
    public void deductStock(@RequestBody List<OrderDetailDTO> items){
        itemService.deductStock(items);
    }
}
